package com.smasher.camera.fragment

import android.os.Bundle
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.camera.core.AspectRatio
import androidx.camera.core.CameraSelector
import androidx.camera.core.ImageAnalysis
import androidx.camera.core.resolutionselector.AspectRatioStrategy
import androidx.camera.core.resolutionselector.ResolutionSelector
import androidx.camera.view.LifecycleCameraController
import androidx.fragment.app.Fragment
import com.smasher.camera.analyzer.MLQRcodeAnalyzer
import com.smasher.camera.analyzer.QRcodeAnalyzer
import com.smasher.camera.databinding.FragmentQrcodeBinding
import java.util.concurrent.Executors
import kotlin.math.abs
import kotlin.math.max
import kotlin.math.min

class QRcodeFragment : Fragment() {


    private var useMlKitDetector = false

    private val cameraExecutor = Executors.newSingleThreadExecutor()

    lateinit var mBinding: FragmentQrcodeBinding

    lateinit var cameraController: LifecycleCameraController

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        arguments?.let {
            useMlKitDetector = it.getBoolean("useMlKitDetector", false)
        }
    }

    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View {
        mBinding = FragmentQrcodeBinding.inflate(inflater, container, false)
        return mBinding.root
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)

//        val rotation = mBinding.viewFinder.display.rotation

        val cameraSelector = CameraSelector.Builder()
            .requireLensFacing(CameraSelector.LENS_FACING_BACK)
            .build()

        val aspectRatioStrategy = AspectRatioStrategy(
            AspectRatio.RATIO_16_9, AspectRatioStrategy.FALLBACK_RULE_AUTO
        )
        val resolutionSelector = ResolutionSelector.Builder()
            .setAspectRatioStrategy(aspectRatioStrategy)
            .setAllowedResolutionMode(ResolutionSelector.PREFER_HIGHER_RESOLUTION_OVER_CAPTURE_RATE)
            .build()

        cameraController = LifecycleCameraController(requireContext())
        cameraController.cameraSelector = cameraSelector
        cameraController.previewResolutionSelector = resolutionSelector
        cameraController.imageAnalysisResolutionSelector = resolutionSelector
        cameraController.setImageAnalysisAnalyzer(cameraExecutor, createAnalyzer())
        cameraController.bindToLifecycle(this)
        mBinding.viewFinder.controller = cameraController

    }

    private fun onResult(value: String) {
        mBinding.qrResult.post {
            if (mBinding.qrResult.text == value) return@post
            mBinding.qrResult.text = value
        }
    }

    /**
     *  [androidx.camera.core.ImageAnalysis.Builder] requires enum value of
     *  [androidx.camera.core.AspectRatio.Ratio]. Currently it has values of 4:3 & 16:9.
     *
     *  Detecting the most suitable ratio for dimensions provided in @params by counting absolute
     *  of preview ratio to one of the provided values.
     *
     *  @param width - preview width
     *  @param height - preview height
     *  @return suitable aspect ratio
     */
    private fun aspectRatio(width: Int, height: Int): Int {
        val previewRatio = max(width, height).toDouble() / min(width, height)
        if (abs(previewRatio - RATIO_4_3_VALUE) <= abs(previewRatio - RATIO_16_9_VALUE)) {
            return AspectRatio.RATIO_4_3
        }
        return AspectRatio.RATIO_16_9
    }

    override fun onDestroy() {
        super.onDestroy()
        cameraController.unbind()
        cameraExecutor.shutdown()
    }


    private fun createAnalyzer(): ImageAnalysis.Analyzer {
        return if (useMlKitDetector) {
            Log.i(TAG, "use MLQRcodeAnalyzer")
            MLQRcodeAnalyzer(this::onResult)
        } else {
            Log.i(TAG, "use QRcodeAnalyzer")
            QRcodeAnalyzer(this::onResult)
        }
    }

    companion object {

        private const val TAG = "QRcodeFragment"
        private const val RATIO_4_3_VALUE = 4.0 / 3.0
        private const val RATIO_16_9_VALUE = 16.0 / 9.0


        @JvmStatic
        fun newInstance(useMlKit: Boolean): QRcodeFragment {
            return QRcodeFragment().apply {
                arguments = Bundle().apply {
                    putBoolean("useMlKitDetector", useMlKit)
                }
            }
        }
    }
}